package cn.bellychang.bobo.queue;

import cn.bellychang.bobo.arraylist.Iterator;
import cn.bellychang.bobo.queue.Queue;

/**
 * @author ChangLiang
 * @date 2020/9/9
 */
public class LinkedListWithTailQueue<E> implements Queue<E> {

    private LinkedList list;

    public LinkedListWithTailQueue() {
        list = new LinkedList();
    }

    @Override
    public int getSize() {
        return list.getSize();
    }

    @Override
    public boolean isEmpty() {
        return list.getSize() == 0;
    }

    @Override
    public void enqueue(E e) {
        list.addLast(e);
    }

    @Override
    public E dequeue() {
        return list.removeFirst();
    }

    @Override
    public E getFront() {
        return list.getFirst();
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Queue Head {");
        Iterator<E> iterator = list.iterator();
        while (iterator.hasNext()) {
            builder.append(iterator.next());
            if (iterator.hasNext()) {
                builder.append("<-");
            }
        }
        return builder.append("} Tail").toString();
    }

    class LinkedList {

        /**
         * 标识要读取的位置
         */
        private Node head;

        /**
         * 标识要写入的位置
         */
        private Node tail;

        private int size;

        public LinkedList() {
            Node dummyNode = new Node();
            head = tail = dummyNode;
        }

        public int getSize() {
            return this.size;
        }

        public void addLast(E e) {
            Node newNode = new Node();
            newNode.value = e;
            if (size == 0) {
                head = newNode;
                tail = newNode;
            } else {
                tail.next = newNode;
                tail = newNode;
            }
            size++;
        }

        public E getFirst() {
            checkIsEmpty();
            return head.value;
        }

        public E removeFirst() {
            checkIsEmpty();
            Node temp = head;
            head = head.next;
            size--;
            return temp.value;
        }

        private void checkIsEmpty() {
            if (size == 0) {
                throw new RuntimeException("empty linkedlist");
            }
        }

        public Iterator<E> iterator() {
            return new Iterator<E>() {

                Node temp = head;

                int count;

                @Override
                public boolean hasNext() {
                    return count < size;
                }

                @Override
                public E next() {
                    Node value = temp;
                    temp = temp.next;
                    count++;
                    return value.value;
                }
            };
        }

        class Node {
            private E value;

            private Node next;
        }
    }
}
